package com.giantlizard.cloud.base.aspects;

import com.giantlizard.cloud.base.annotation.RateLimit;
import com.giantlizard.cloud.base.constants.RedisConstants;
import com.giantlizard.cloud.redis.utils.RedisOperator;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.aspectj.lang.annotation.Aspect;

import javax.servlet.http.HttpServletRequest;

@Aspect
@Slf4j
@Component
public class RateLimitAspect {

    private final RedisOperator redisOperator;
    private final HttpServletRequest request;

    public RateLimitAspect(RedisOperator redisOperator, HttpServletRequest request) {
        this.redisOperator = redisOperator;
        this.request = request;
    }

    @Around("@annotation(rateLimit)")
    public Object around(ProceedingJoinPoint point, RateLimit rateLimit) throws Throwable {
        String ip = request.getRemoteAddr();
        // 尝试获取锁，如果获取失败，则表示请求频率过高
        MethodSignature signature = (MethodSignature) point.getSignature();
        String methodName = signature.getMethod().getName();
        String key = RedisConstants.RATE_LIMIT_PREFIX_KEY+ RedisConstants.REDIS_CONCAT + ip + RedisConstants.REDIS_CONCAT + methodName;
        if (redisOperator.exists(key)) {
           if(redisOperator.incr(key,1)>rateLimit.maxRequests()){
               throw new RuntimeException(rateLimit.message());
           }
        }else{
            redisOperator.set(key,1,rateLimit.timeWindow());
        }
        return point.proceed();
    }
}
